﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ComputerArchitecture.Core;
using ComputerArchitecture.Core.Logging;
using ComputerArchitecture.Numbers;
using ComputerArchitecture.Units.Integers.Signed.Interfaces;

namespace ComputerArchitecture.Units.Integers.Signed.Implementations
{
    public class SignedSubstractUnit : LoggingObject, ISignedSubstractUnit
    {
        #region Fields

        private readonly ISignedAdderUnit _adderUnit;
        private readonly ISignedNegateUnit _negateUnit;

        #endregion

        #region Constructors

        public SignedSubstractUnit(ILoggingService loggingService, ISignedAdderUnit signedAdderUnit, ISignedNegateUnit signedNegateUnit) 
            : base(loggingService)
        {
            ArgumentValidator.NullValidate(signedAdderUnit, "signedAdderUnit");
            _adderUnit = signedAdderUnit;
            ArgumentValidator.NullValidate(signedNegateUnit, "signedNegateUnit");
            _negateUnit = signedNegateUnit;
        }

        public SignedSubstractUnit(ILoggingService loggingService)
            : this(loggingService, new SignedAdderUnit(loggingService), new SignedNegateUnit(loggingService))
        {
        }

        #endregion

        IBitNumber ISubstractUnit.Substract(IBitNumber first, IBitNumber second, out bool overflow)
        {
            return this.Substract((ISignedBitNumber) first, (ISignedBitNumber) second, out overflow);
        }

        public ISignedBitNumber Substract(ISignedBitNumber first, ISignedBitNumber second, out bool overflow)
        {
            ArgumentValidator.NullValidate(first);
            ArgumentValidator.NullValidate(second);
            bool hasError = false;
            NegateSpecialCase specialCase;
            ISignedBitNumber negateSecond = _negateUnit.Negate(second, out specialCase, out hasError);
            ISignedBitNumber result = _adderUnit.Add(first, negateSecond, out overflow);
            if (hasError && specialCase == NegateSpecialCase.MaxNegativeValue)
            {
                overflow = true;
            }
            return result;
        }

        public ISignedBitNumber Dec(ISignedBitNumber number, out bool overflow)
        {
            var one = SignedBitNumber.GetOne(number.Size);
            return this.Substract(number, one, out overflow);
        }
    }
}
